package com.pansoft.openplanet.account.util;

import com.efounder.util.AppContext;
import com.pansoft.openplanet.account.model.ActGeneratorBean;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.chainlib.achain.data.ACTPrivateKey;
import com.pansoft.openplanet.chainlib.achain.util.MyByte;
import com.pansoft.openplanet.db.AccountDao;
import com.pansoft.openplanet.util.EthHDWalletUtils;
import com.pansoft.openplanet.util.TCAccountManager;

import org.bitcoinj.wallet.DeterministicSeed;
import org.web3j.crypto.ECKeyPair;

import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

/**
 * Achain（act）账户生成
 *
 * @author YQS 2018/09/03
 */
public class ActAccountGenerator {
    private static final String TAG = "ActAccountGenerator";


    /**
     * todo 异步方法创建账户
     *
     * @return
     * @throws Exception
     */
    public static Disposable createAccountAsync(final GeneratorListener generatorListener) {


        Disposable disposable = Observable.create(new ObservableOnSubscribe<ActGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<ActGeneratorBean> emitter) throws Exception {
                ActGeneratorBean ActGeneratorBean = createActAccountSync();
                emitter.onNext(ActGeneratorBean);
                emitter.onComplete();
            }
        })        // 在io线程生成walletfile的进行操作
                .subscribeOn(Schedulers.io())
                // 在主线程处理walletfile保存
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<ActGeneratorBean>() {
                    @Override
                    public void accept(@NonNull ActGeneratorBean ActGeneratorBean) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorSuccess(ActGeneratorBean);
                        }

                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * todo 同步方法创建 账户
     *
     * @return
     * @throws Exception
     */
    public static ActGeneratorBean createActAccountSync() throws Exception {
        DeterministicSeed ds = EthHDWalletUtils.createRandomDeterministicSeed("");
        List<String> mnemonicList = ds.getMnemonicCode();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < mnemonicList.size(); i++) {
            stringBuffer.append(mnemonicList.get(i)).append(" ");
        }
        String mnemonic = stringBuffer.substring(0, stringBuffer.length() - 1);
        //生成密钥
        ECKeyPair ecKeyPair = EthHDWalletUtils.createECKeyPairFromSeed(ds);

        String privateKey = ecKeyPair.getPrivateKey().toString(16);
        ACTPrivateKey actPrivateKey = new ACTPrivateKey(MyByte.fromHex(privateKey));
        String publicKey = actPrivateKey.getPublicKey(true).toString();
        String keyStr = actPrivateKey.getKeyStr();
        String secretPrikey = TCAccountManager.encryptByMainPrivKey("0x" + privateKey);
        String secretMnemonic = TCAccountManager.encryptByMainPrivKey(mnemonic);
        String address = actPrivateKey.getAddress().getAddressStr();
        ActGeneratorBean actGeneratorBean = new ActGeneratorBean();

        actGeneratorBean.setWalletAddress(address)
                .setPrivateKey("0x" + privateKey)
                .setPublicKey("0x" + publicKey)
                .setSecretPriKey(secretPrikey)
                .setMnemonic(mnemonic)
                .setMnemonicList(mnemonicList)
                .setSecretMnemonic(secretMnemonic)
                .setSecretPriKey(secretPrikey);
        actGeneratorBean.setActKeyStr(keyStr);

        return actGeneratorBean;
    }

    /**
     * todo 使用助记词恢复钱包
     *
     * @param mnemoric          助记词（" "分割）
     * @param generatorListener
     * @return
     */
    public static Disposable recoverAccountByMnemoric(final String mnemoric,
                                                      final GeneratorListener generatorListener) {
        Disposable disposable = Observable.create(new ObservableOnSubscribe<ActGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<ActGeneratorBean> emitter) throws Exception {
                //助记词恢复
                String privateKey = EthHDWalletUtils.generatePrivateKey(mnemoric, "");
                ACTPrivateKey actPrivateKey = new ACTPrivateKey(MyByte.fromHex(privateKey));
                String publicKey = MyByte.toHex(actPrivateKey.getPublicKey(true));
                String keyStr = actPrivateKey.getKeyStr();
                String secretPrikey = TCAccountManager.encryptByMainPrivKey("0x" + privateKey);
                String secretMnemonic = TCAccountManager.encryptByMainPrivKey(mnemoric);
                String address = actPrivateKey.getAddress().getAddressStr();
                ActGeneratorBean actGeneratorBean = new ActGeneratorBean();

                actGeneratorBean.setWalletAddress(address)
                        .setPrivateKey("0x" + privateKey)
                        .setPublicKey("0x" + publicKey)
                        .setSecretPriKey(secretPrikey)
                        .setMnemonic(mnemoric)
                        .setSecretMnemonic(secretMnemonic)
                        .setSecretPriKey(secretPrikey);
                actGeneratorBean.setActKeyStr(keyStr);

                emitter.onNext(actGeneratorBean);
                emitter.onComplete();
            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<ActGeneratorBean>() {
                    @Override
                    public void accept(ActGeneratorBean actGeneratorBean) throws Exception {

                        generatorListener.generatorSuccess(actGeneratorBean);

                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;
    }

    /**
     * todo 使用私钥恢复钱包
     *
     * @param key               私钥
     * @param generatorListener
     * @return
     */
    public static Disposable recoverAccountByPrivateKey(String key,
                                                        final GeneratorListener generatorListener) {
        final String finalPrivateKey = key;
        Disposable disposable = Observable.create(new ObservableOnSubscribe<ActGeneratorBean>() {
            @Override
            public void subscribe(ObservableEmitter<ActGeneratorBean> emitter) throws Exception {
                ActGeneratorBean actGeneratorBean = recoverByPrivateKeySync(finalPrivateKey);


                emitter.onNext(actGeneratorBean);
                emitter.onComplete();

            }

        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<ActGeneratorBean>() {
                    @Override
                    public void accept(ActGeneratorBean actGeneratorBean) throws Exception {

                        generatorListener.generatorSuccess(actGeneratorBean);

                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (generatorListener != null) {
                            generatorListener.generatorFail();
                        }
                    }
                });
        return disposable;

    }
    
    /**
     * 私钥恢复钱包 同步方法
     */
    public static ActGeneratorBean recoverByPrivateKeySync(String finalPrivateKey) {

        try {
            if (finalPrivateKey.length() > 2) {
                if ("0x".equals(finalPrivateKey.substring(0, 2).toLowerCase())) {
                    //去掉0X
                    finalPrivateKey = finalPrivateKey.substring(2, finalPrivateKey.length());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        ACTPrivateKey actPrivateKey = new ACTPrivateKey(MyByte.fromHex(finalPrivateKey));
        String publicKey = MyByte.toHex(actPrivateKey.getPublicKey(true));
        String keyStr = actPrivateKey.getKeyStr();
        String secretPrikey = TCAccountManager.encryptByMainPrivKey("0x" + finalPrivateKey);
        String address = actPrivateKey.getAddress().getAddressStr();
        ActGeneratorBean actGeneratorBean = new ActGeneratorBean();

        actGeneratorBean.setWalletAddress(address)
                .setPrivateKey("0x" + finalPrivateKey)
                .setPublicKey("0x" + publicKey)
                .setSecretPriKey(secretPrikey);
        actGeneratorBean.setActKeyStr(keyStr);
        return actGeneratorBean;
    }

    /**
     * 备份act私钥
     *
     * @param address
     * @param listener
     * @return
     */
    public static Disposable backUpPrivateKey(final String address, final BackUpPrivateKeyListener listener) {
        Disposable disposable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(final ObservableEmitter<String> emitter) throws Exception {
                Account account = new AccountDao(AppContext.getInstance()).getAccount(address);
                if (account != null) {
                    String secretPrivateKey = account.getSecretPrivateKey();
                    String privateKey = TCAccountManager.decryptByMainPrivKey(secretPrivateKey);
                    emitter.onNext(privateKey);
                    emitter.onComplete();
                } else {
                    emitter.onNext(null);
                    emitter.onComplete();
                }
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        if (listener != null) {
                            listener.backUpSuccess(s);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        if (listener != null) {
                            listener.onfail("备份私钥失败");
                        }
                    }
                });
        return disposable;
    }

    /**
     * 钱包创建恢复的回调
     */
    public interface GeneratorListener {
        //成功
        void generatorSuccess(ActGeneratorBean actGeneratorBean);

        //失败
        void generatorFail();
    }

    /**
     * 钱包备份私钥的回调
     */
    public interface BackUpPrivateKeyListener {
        //成功
        void backUpSuccess(String privateKey);

        //失败
        void onfail(String msg);
    }
}
